#pragma once

void* AllocateMemory(const unsigned int i_size);
void DeallocateMemory(void* i_mem);

//inline void* operator new(size_t i_size)
//{
//	return AllocateMemory(i_size);
//}
//
//inline void operator delete(void* i_mem)
//{
//	DeallocateMemory(i_mem);
//}
//
//inline void* operator new[](size_t i_size)
//{
//	return AllocateMemory(i_size);
//}
//
//inline void operator delete[](void* i_mem)
//{
//	DeallocateMemory(i_mem);
//}
//
template<class T> struct NonConst { typedef T non_const_type; };
template<class T> struct NonConst<const T> { typedef T non_const_type; };

template<typename T>
inline T* NewA(const unsigned int i_num)
{
	void* mem = AllocateMemory(i_num*sizeof(T) + sizeof(unsigned int));
	if(!mem)
		return NULL;

	T* startArray = (T*)((unsigned char*)(mem) + sizeof(unsigned int));
	T* currentElement = startArray;

	for(unsigned int i=0; i < i_num; ++i)
		new(currentElement++) T;

	return startArray;
}

template<typename T>
inline void Delete(T* const i_ptr)
{
	if (i_ptr) 
	{
		typedef typename NonConst<T>::non_const_type NCT;
		NCT* ptr = const_cast<NCT*>(i_ptr);
		ptr->~NCT();
		DeallocateMemory(ptr);
	}
}

template<>
inline void Delete<void>(void* const i_ptr)
{
	if (i_ptr)
	{
		DeallocateMemory(i_ptr);
	}
}

template<typename T>
inline void DeleteA(T* const i_ptr)
{
	if (i_ptr)
	{
		void* startMem = (void*)((unsigned char*)(i_ptr)-sizeof(unsigned int));
		typedef typename NonConst<T>::non_const_type NCT;
		const unsigned int num = *(const unsigned int*)startMem;
		for(unsigned int  i=0; i<num; ++i)
		{
			NCT* ptr = const_cast<NCT*>(i_ptr);
			ptr->~NCT();
		}
		DeallocateMemory(startMem);
	}
}

#define Z_NEW new
#define Z_NEW_A(T,N) NewA<T>(N)
#define Z_DELETE(ptr) Delete(ptr)
#define Z_DELETE_A(ptr) DeleteA(ptr)










